package br.xraylol.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;

import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.NTCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.HttpClientBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import br.xraylol.constant.FileProperties;
import br.xraylol.constant.ServiceType;
import br.xraylol.util.Properties;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

@Component
public class GenericClient {

	@Autowired(required = true)
	private RestTemplate restTemplate;

	@Autowired(required = true)
	private ObjectMapper objectMapper;

	protected String uri;

	private Properties lolPathProperties;
	private Properties proxyProperties;

	public GenericClient() {

	}

	public GenericClient(ServiceType serviceType) {
		lolPathProperties = new Properties(FileProperties.LOL_PATH_PARAMETERS);
		proxyProperties = new Properties(FileProperties.PROXY_PARAMETERS);
		this.uri = replacePathParameters(serviceType);
	}

	private String replacePathParameters(ServiceType serviceType) {
		return lolPathProperties.getValue("uri.restful.service.lol").trim()
				+ serviceType
						.getUri()
						.replace("{region}", lolPathProperties.getValue("region"))
						.replace("{version}",
								lolPathProperties.getValue(serviceType.getVersionParameter()));
	}

	protected <T> T findAll(String additionUri, Class<T> classType) {
		return findAll(additionUri, classType, false);
	}
	
	protected <T> T findAll(String additionUri, Class<T> classType, Boolean hasConcatParameterUri) {
		try {
			String fullUri = getFullUri(additionUri, hasConcatParameterUri);
			HttpComponentsClientHttpRequestFactory factory = getFactory();

			if (factory != null) {
				restTemplate.setRequestFactory(factory);
			}

			HttpHeaders headers = new HttpHeaders();
			headers.add("Accept", MediaType.APPLICATION_JSON_VALUE);
			HttpEntity<String> request = new HttpEntity<String>(headers);
			ResponseEntity<String> response = restTemplate.exchange(fullUri, HttpMethod.GET, request, String.class);
			String responseBody = response.getBody();
			try {
				objectMapper.configure(MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME, true);
				objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
				return objectMapper.readValue(responseBody, classType);
				
			} catch (IOException e) {
				throw new RuntimeException(e);
			}
		} catch (Exception ex) {
			System.out.println(ex.getMessage());
		}

		return null;
	}

	private HttpComponentsClientHttpRequestFactory getFactory() {

		HttpComponentsClientHttpRequestFactory factory = null;
		String host = proxyProperties.getValue("proxy.host");
		Integer port = Integer.parseInt(proxyProperties.getValue("proxy.port"));
		String domain = proxyProperties.getValue("proxy.domain");
		String user = proxyProperties.getValue("proxy.user");
		String password = proxyProperties.getValue("proxy.password");

		if (host != null && !host.isEmpty()) {
			factory = new HttpComponentsClientHttpRequestFactory();
			HttpHost proxy = new HttpHost(host, port);
			CredentialsProvider provider = new BasicCredentialsProvider();
			NTCredentials creds = new NTCredentials(user, password, "workstation", domain);
			provider.setCredentials(new AuthScope(proxy), creds);

			HttpClient httpClient = HttpClientBuilder.create().setProxy(proxy)
					.setDefaultCredentialsProvider(provider).build();

			factory.setHttpClient(httpClient);
		}

		return factory;
	}

	private String getFullUri(String additionUri, Boolean hasConcatParameterUri) {
		// URI
		String fullUri = uri.trim() + additionUri.trim();

		if (hasConcatParameterUri) {
			fullUri += "&";
		} else {
			fullUri += "?";
		}

		fullUri += "api_key=" + lolPathProperties.getValue("api.key");
		return fullUri;
	}

	protected String getJSON(String additionUri, Boolean hasConcatParameterUri) {
		try {
			String fullUri = getFullUri(additionUri, hasConcatParameterUri);

			URL url = new URL(fullUri);
			HttpURLConnection connection = (HttpURLConnection) url.openConnection();
			connection.setRequestMethod("GET");
			connection.setRequestProperty("Accept", "application/json");

			InputStream json = connection.getInputStream();

			BufferedReader br = new BufferedReader(new InputStreamReader(json));
			StringBuilder sb = new StringBuilder();
			String line;
			while ((line = br.readLine()) != null) {
				sb.append(line + "\n");
			}
			br.close();
			String response = sb.toString();

			connection.disconnect();

			return response;
		} catch (Exception ex) {
			System.out.println(ex.getMessage());
		}

		return null;
	}
}
